
// 13.28

#include "802_1Q_2005_procedures.h"
#include "bridge.h"
#include "port.h"
#include "assert.h"

enum
{
	UNDEFINED,
	DISCARD,
	RECEIVE,
};

// ============================================================================

const char*	PortReceive_802_1Q_2005_GetStateName (SM_STATE state)
{
	switch (state)
	{
		case DISCARD:	return "DISCARD";
		case RECEIVE:	return "RECEIVE";
		default:		return "(undefined)";
	}
}

// ============================================================================

// When this function returns a valid state (non-zero), it means it has changed one or more variables, so all state machines must be run again.
SM_STATE PortReceive_802_1Q_2005_CheckConditions (BRIDGE* bridge, int givenPort, int givenTree, SM_STATE state)
{
	assert (givenPort != -1);
	assert (givenTree == -1);

	PORT* port = bridge->ports [givenPort];
	
	// ------------------------------------------------------------------------
	// Check global conditions.
	
	if (bridge->BEGIN || ((port->rcvdBpdu || port->edgeDelayWhile != bridge->MigrateTime) && !port->portEnabled)) // bug in the doc!!! - one paranthesis too much
	{
		if (state == DISCARD)
		{
			// The entry block for this state has been executed already.
			return 0;
		}
		
		return DISCARD;
	}
	
	// ------------------------------------------------------------------------
	// Check exit conditions from each state.

	if (state == DISCARD)
	{
		if (port->rcvdBpdu && port->portEnabled)
			return RECEIVE;
		
		return 0;
	}
	
	if (state == RECEIVE)
	{
		if (port->rcvdBpdu && port->portEnabled && !rcvdAnyMsg (bridge, givenPort))
			return RECEIVE;
		
		return 0;
	}
	
	assert (false);
	return 0;
}

// ============================================================================

void PortReceive_802_1Q_2005_InitState (BRIDGE* bridge, int givenPort, int givenTree, SM_STATE state)
{
	assert (givenPort != -1);
	assert (givenTree == -1);

	PORT* port = bridge->ports [givenPort];
	
	if (state == DISCARD)
	{
		port->rcvdBpdu = port->rcvdRSTP = port->rcvdSTP = false;
		clearAllRcvdMsgs (bridge, givenPort);
		port->edgeDelayWhile = bridge->MigrateTime;
	}
	else if (state == RECEIVE)
	{
		updtBPDUVersion (bridge, givenPort);
		port->rcvdInternal = fromSameRegion (bridge, givenPort);
		setRcvdMsgs (bridge, givenPort);
		port->operEdge = port->rcvdBpdu = false;
		port->edgeDelayWhile = bridge->MigrateTime;
	}
	else
		assert (false);
}